
/********************************************* 
*hellodev.c 
*********************************************/  
#include <linux/module.h>  
#include <linux/ioctl.h>  
#include <linux/wait.h> 
#include <linux/poll.h> 
#include <linux/device.h> 
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/mm.h>  
#include <linux/sched.h>  
#include <linux/init.h>  
#include <linux/cdev.h>  
#include <asm/io.h>  
//#include <asm/system.h>  
//#include <asm/uaccess.h>  
 #include<linux/slab.h> 
  
static int hello_major = 234; 

static struct class *hello_class;

#define  DEV_NAME "hello_cls" 

module_param(hello_major,int,S_IRUGO);  

dev_t devno;

struct cdev cdev;  
int num;
int flage=0;
char kbuf[128];

wait_queue_head_t rwq; //read wq
wait_queue_head_t wwq;  //write wq

char *mystr = "default";

//module_param(kbuf, charp, S_IRUGO);  
module_param(mystr, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);  

int hello_open(struct inode *inode,struct file *filp)  
{   
  	return 0;  
}  

int hello_release(struct inode *inode,struct file *filp)  
{  
    	return 0;  
}  

/*******************************************************
 *
 *	wait_event_interruptible 使当前进程睡眠，除非满足 flage 非 0 
 *	
 *	
 *
****************************************************/

static ssize_t hello_read(struct file *filp,char __user *buf,size_t size,loff_t *poss)  
{
  printk("[%s] %s\n",__func__, mystr);  
//  int ret = 0;

  if(flage==0)
  {
    if(filp->f_flags & O_NONBLOCK)
    {
      return -EAGAIN;
    }
    wait_event_interruptible(rwq,flage!=0);
  } 

  if(copy_to_user(buf,kbuf,size)) 
  {
    return -EFAULT;
  }

  flage=0;

  wake_up_interruptible(&wwq);
  return size; 
}   

static ssize_t hello_write(struct file *filp,const char __user *buf,size_t size,loff_t *poss)  
{  
//    int ret = 0;
  if(size>128||size<0)
  {
    	return -EINVAL;
  }

  wait_event_interruptible(wwq,flage!=1);

  if(copy_from_user(kbuf,buf,size)) 
  {
    return -EFAULT;
  }

  flage=1;
  wake_up_interruptible(&rwq);
  return size;  
}  
 
static const struct file_operations hello_fops =  
{  
    .owner  = THIS_MODULE,  
    .read   = hello_read,  
    .write  = hello_write,  
    .open   = hello_open,  
    .release = hello_release,  
};   

static int hellodev_init(void)  
{  
  int result;  
//  int i;  
  struct device *hello_dev;

  printk("[%s] mystr: %s\n", __func__,mystr);

  devno = MKDEV(hello_major,0);  

  if(hello_major)  
      result = register_chrdev_region(devno,2,"hello");  
  else    
  {  
      result = alloc_chrdev_region(&devno,0,2,"hello");  
      hello_major = MAJOR(devno);  
  }  
  
  if(result < 0)  
      return result;    

  cdev_init(&cdev,&hello_fops);  
  cdev.owner = THIS_MODULE;  
  cdev.ops = &hello_fops;    

  cdev_add(&cdev,MKDEV(hello_major,0),1);  
  init_waitqueue_head(&rwq);
  init_waitqueue_head(&wwq);

  hello_class = class_create(THIS_MODULE, DEV_NAME);//类名字 
  
  if (IS_ERR(hello_class)) {
    printk(KERN_WARNING "class_create faihello ! \n");
    goto err_3;
  }

  hello_dev = device_create(hello_class, NULL, devno, NULL, "hello");
  
  if (IS_ERR(hello_dev)) {
    printk(KERN_WARNING "device_create faihello! \n");
    goto err_4;
  }
  return 0; 

err_4:
  class_destroy(hello_class);

err_3:
  cdev_del(&cdev);
  unregister_chrdev_region(MKDEV(hello_major,0),2);   
  return 0;  
}  


static void hellodev_exit(void)  
{ 
  device_destroy(hello_class, devno);  
  class_destroy(hello_class);
  cdev_del(&cdev);
  unregister_chrdev_region(MKDEV(hello_major,0),2);  
}    

MODULE_LICENSE("GPL");
module_init(hellodev_init);  
module_exit(hellodev_exit);  

